package net.qiqbframework.commandhandling;

import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.commandhandling.callbacks.LoggingCallback;
import net.qiqbframework.commandhandling.callbacks.NoOpCallback;
import net.qiqbframework.common.transaction.NoTransactionManager;
import net.qiqbframework.common.transaction.TransactionManager;
import net.qiqbframework.config.Configuration;
import net.qiqbframework.messaging.monitoring.MessageMonitor;
import net.qiqbframework.messaging.monitoring.NoOpMessageMonitor;
import net.qiqbframework.messaging.task.RollbackConfiguration;
import net.qiqbframework.messaging.task.RollbackConfigurationType;
import net.qiqbframework.tracing.NoOpSpanFactory;

import javax.annotation.Nonnull;

import static net.qiqbframework.common.BuilderUtils.assertNonNull;
import static net.qiqbframework.common.utils.ObjectUtil.getOrDefault;


@Slf4j
public class DefaultCommandBusBuilder {

    protected TransactionManager transactionManager = NoTransactionManager.INSTANCE;
    protected MessageMonitor<? super CommandMessage<?>> messageMonitor = NoOpMessageMonitor.INSTANCE;
    protected RollbackConfiguration rollbackConfiguration = RollbackConfigurationType.UNCHECKED_EXCEPTIONS;
    protected DuplicateCommandHandlerResolver duplicateCommandHandlerResolver = DuplicateCommandHandlerResolution.rejectDuplicates();
    protected CommandCallback<Object, Object> defaultCommandCallback = LoggingCallback.INSTANCE;
    protected CommandBusSpanFactory builderSpanFactory = DefaultCommandBusSpanFactory.builder().spanFactory(NoOpSpanFactory.INSTANCE).build();
    protected final Configuration configuration;

    public DefaultCommandBusBuilder(Configuration configuration) {
        this.configuration = configuration;
    }

    public DefaultCommandBusBuilder transactionManager(@Nonnull TransactionManager transactionManager) {
        assertNonNull(transactionManager, "TransactionManager may not be null");
        this.transactionManager = transactionManager;
        return this;
    }


    public DefaultCommandBusBuilder messageMonitor(@Nonnull MessageMonitor<? super CommandMessage<?>> messageMonitor) {
        assertNonNull(messageMonitor, "MessageMonitor may not be null");
        this.messageMonitor = messageMonitor;
        return this;
    }

    public DefaultCommandBusBuilder rollbackConfiguration(@Nonnull RollbackConfiguration rollbackConfiguration) {
        assertNonNull(rollbackConfiguration, "RollbackConfiguration may not be null");
        this.rollbackConfiguration = rollbackConfiguration;
        return this;
    }


    public DefaultCommandBusBuilder duplicateCommandHandlerResolver(@Nonnull DuplicateCommandHandlerResolver duplicateCommandHandlerResolver) {
        assertNonNull(duplicateCommandHandlerResolver, "DuplicateCommandHandlerResolver may not be null");
        this.duplicateCommandHandlerResolver = duplicateCommandHandlerResolver;
        return this;
    }


    public DefaultCommandBusBuilder defaultCommandCallback(@Nonnull CommandCallback<Object, Object> defaultCommandCallback) {
        this.defaultCommandCallback = getOrDefault(defaultCommandCallback, NoOpCallback.INSTANCE);
        return this;
    }


    public DefaultCommandBusBuilder spanFactory(@Nonnull CommandBusSpanFactory spanFactory) {
        assertNonNull(spanFactory, "SpanFactory may not be null");
        this.builderSpanFactory = spanFactory;
        return this;
    }

    public DefaultCommandBus build() {
        return new DefaultCommandBus(this);
    }


    protected void validate() {
        // Method kept for overriding
    }

}
